#include "networkmanager.h"
#include "networkpostrequest.h"
#include "networkgetrequest.h"
#include "networkmanager.h"
#include "zingme/networkzingmeconnection.h"
#include "zingme/networkzingmemanager.h"


#include <json.h>

#include <QDate>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QTextStream>
#include <QThread>
#include <QVariant>
#include <QTimer>

namespace Account{
class Manager;
}

namespace Network {

Manager *Manager::m_instance = NULL;
QString Manager::m_server = QString("chat.realtime.me.zing.vn");
int Manager::m_port = 5050;


//QString Manager::m_server = QString("ws://49.213.67.22");
//int Manager::m_port = 8181;

Manager::Manager(QObject *parent) :
    QObject(parent),
    m_connection(NULL),
    m_manager(new QNetworkAccessManager(this)),
    m_worker(new QThread),
    m_sessionKey(),
    m_wantDisconnect(false)
{
    m_worker->start();
    //  connect(Account::Manager::instance(), &Account::Manager::logined,
    //          this, &Manager::onLogined);
}


Manager *Manager::instance(QObject *parent)
{
    if (m_instance == NULL)
        m_instance = new Zingme::Manager(parent);
    return m_instance;
}


bool Manager::post(Request *request)
{
    return request->post(this);
}


void Manager::onLogined(bool successed, const QString &message, const QString &sessionKey)
{
    Q_UNUSED(message)
    if (!successed)
        return;

    m_sessionKey = sessionKey;
    if (m_connection == NULL) {
        m_connection = new Zingme::Connection(this);
        connect(m_connection,
                &Connection::connected,
                this,
                &Manager::onConnected);

        connect(m_connection,
                &Connection::received,
                this,
                &Manager::onReceived);

        connect(m_connection,
                &Connection::disconnected,
                this,
                &Manager::onDisconnected);

        // connect(Account::Manager::instance(),
        //         &Account::Manager::logouted,
        //         this,
        //         &Manager::onLogouted);
    }
    qDebug() << "do connect to websocket " << sessionKey;
    m_connection->connect(Manager::m_server, Manager::m_port, params());
    emit sessionKeyReady();

    emit connected();

    m_wantDisconnect = false;
    this->reconnect();
}


void Manager::onLogouted()
{
    logout();
}


void Manager::logout()
{
    m_sessionKey = QString();// FixMe: call server to destroy session
    if (m_connection == NULL)
        return;

    m_wantDisconnect = true;
    m_connection->disconnect();
    delete m_connection;
    m_connection = NULL;
}

bool Manager::getNextEndpoint(Endpoint &endpoint)
{
    if (this->m_serverEnpoints.size() == 0)
        return false;
    static int currentEndpoint = 0;
    if (currentEndpoint >= this->m_serverEnpoints.size() || currentEndpoint < 0)
        currentEndpoint = 0;
    endpoint = this->m_serverEnpoints.at(currentEndpoint);
    return true;

}

void Manager::reconnect()
{
    //
    Endpoint aEndpoint;
    if (this->getNextEndpoint(aEndpoint))
    {
        m_connection->connect(aEndpoint.host, aEndpoint.port, params());
    }
    //m_connection->connect(Manager::m_server, Manager::m_port, params());
}


void Manager::onConnected()
{
    /*
     * Test  + fix cho nay sau
     *
     */
    //    if (m_connection == NULL)
    //        return;
    //    emit connected();
}


void Manager::onReceived(QByteArray message)
{
    qDebug() <<"void Manager::onReceived" << message;
    JsonReader reader;
    QTextStream stream(message);
    QVariant variant;
    if (!reader.read(stream, variant))
        return;

    if (variant.type() != QVariant::Map)
        return;

    QVariantMap map = variant.toMap();
    if (!map.contains("r"))
        return;

    QVariant errorVar = map.value("r");
    if (errorVar.type() != QVariant::String)
        return;

    bool ok;
    int error = errorVar.toString().toInt(&ok);
    if (!ok)
        return;

    if (error != 0)
        return;

    QVariant commandVar = map.value("cmd");
    if (commandVar.type() != QVariant::String)
        return;

    QString commandId = commandVar.toString();
    if (!map.contains("data"))
        return;

    emit received(commandId, map.value("data"));
}


void Manager::onDisconnected()
{
    qDebug() << "Manager::onDisconnected() socket : onDisconnected ";
    emit disconnected();

    if (!m_wantDisconnect)
    {
        qDebug() << "Manager onDisconnected start timer reconnect";
        static QTimer* aTimer = new QTimer(this);
        //aTimer->setInterval(10000);
        aTimer->setSingleShot(true);

        QObject::disconnect(aTimer, &QTimer::timeout, this, &Manager::reconnect );
        QObject::connect(aTimer, &QTimer::timeout, this, &Manager::reconnect );

        aTimer->start(10000);
    }
}

} // namespace Network
